﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TangoGames.Base;
using TangoGames.Scene;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace incubation_xna3d.Enemies
{
    class RedMonster : AnimatedModel, IEnemie, ITurnElement
    {

        #region Fields

        /// <summary>
        /// Ações
        /// </summary>
        public enum Actions { Parado, Andando, Atacando, Morrendo, Morto }

        /// <summary>
        /// Estado atual
        /// </summary>
        Actions state;

        /// <summary>
        /// Esta inativo
        /// </summary>
        bool isIdle = false;

        /// <summary>
        /// Esta Morto
        /// </summary>
        bool isDead = false;

        /// <summary>
        /// Pontos de movimento do Inimigo
        /// </summary>
        private int movementPoints = 5;

        /// <summary>
        /// Variaveis para controle de movimentação
        /// </summary>
        float velocity = 0.4f;
        Vector3 destination = new Vector3();
        Vector3 walkdirection = new Vector3();

        /// <summary>
        /// Posição no tabuleiro
        /// </summary>
        Point boardPosition;

        /// <summary>
        /// Gerenciador da cena corrente
        /// </summary>
        ISceneManager sceneManager;

        #endregion

        #region Properties

        /// <summary>
        /// Posição no tabuleiro
        /// </summary>
        public Point BoardPosition { get { return boardPosition; } set { boardPosition = value; } }

        /// <summary>
        /// Caixa de colisão
        /// </summary>
        public BoundingBox CollisionBox { get { return ModelBoundingBox; } }

        /// <summary>
        /// Gerenciador da cena corrente
        /// </summary>
        public ISceneManager SceneManager { get { return sceneManager; } set { sceneManager = value; } }

        #endregion

        #region Constructor
        /// <summary>
        /// Construtora
        /// </summary>
        /// <param name="game"></param>
        /// <param name="camera"></param>
        public RedMonster(Game game, ICamera camera)
            : base(game, camera, game.Content.Load<Model>("Models/Enemies/monster_Stand"), "Models/Enemies/MonsterCollisionSpheres")
        {
            this.Scale = 4.0f;

            this.Health = 10;

            //this.ShowSpheres = true;

            this.Position = new Vector3(0.0f, 0.0f, 0.0f);

            this.LoadAnimation("Models/Enemies/monster_iDLE");

            this.LoadAnimation("Models/Enemies/monster_walk");

            this.LoadAnimation("Models/Enemies/monster_attack");

            this.LoadAnimation("Models/Enemies/monster_Morto");

            Idle();

            //lista de animações
            //foreach (String b in skinningData.AnimationClips.Keys )
            //{
            //    Console.WriteLine("Redmonster " + b);
            //}

            this.animationPlayer.Stop();

            //animationPlayer.Stop();
            
        }

        #endregion

        #region Interface Enemie

        /// <summary>
        /// Atualiza posição do tabuleiro para posição real
        /// </summary>
        /// <param name="pathMap"></param>
        public void UpdateBoardPosition(IPathMap pathMap)
        {
            Point ini = pathMap.ReversePoint(new Vector2(Position.X, Position.Z));
            Vector2 inireal = pathMap.ConvertPoint(ini);
            boardPosition = ini;
        }

        /// <summary>
        /// centraliza posição no quadrado do tabuleiro
        /// </summary>
        /// <param name="pathMap"></param>
        public void CenterPositionBoardSquare(IPathMap pathMap)
        {
            Vector2 centerPoint = pathMap.ConvertPoint(boardPosition);
            this.Position = new Vector3(centerPoint.X, this.Position.Y, centerPoint.Y);
        }


        public bool Playing { get { return animationPlayer.Playing; } }

        public int MovementPoints { get { return movementPoints; } set { movementPoints = value; } }

        public int CurrentMovementPoints { get; set; }
        public int Health { get; set; }
        public int AttackPower { get; set; }

        public void Stop()
        { animationPlayer.Stop(); }

        public void Play()
        { animationPlayer.Playing = true; }

        public bool Selected(Ray ray)
        {
            return CollisionDetect(ray);
        }

        public bool isVisible(ICharacter other)
        {
            bool result = true;

            Vector3 olho = this.Position + new Vector3(0, this.modelBoundingBox.Max.Y / 2, 0);
            Vector3 olhoInimigo = (other.CollisionBox.Max + other.CollisionBox.Min) / 2;

            // Create a ray from the near clip plane to the far clip plane.
            Vector3 direction = olhoInimigo - olho;
            float distanciaInimigo = direction.Length();

            direction.Normalize();

            Ray ray = new Ray(olho, direction);

            foreach (GameObject3D obj in sceneManager.Stage.StageModels.Values)
            {
                Nullable<float> distance = ray.Intersects(obj.ModelBoundingBox);
                if (distance <= distanciaInimigo)
                {
                    result = false;
                    break;
                }
            }
            return result;
        }

        /// <summary>
        /// Mover para um ponto destino
        /// </summary>
        /// <param name="destination"></param>
        public void MoveTo(Vector3 destination)
        {
            Vector3 direction = destination - this.Position;
            direction.Normalize();
            walkdirection = new Vector3(direction.X, 0, direction.Z);
            this.destination = new Vector3(destination.X, Position.Y, destination.Z);
            this.RotationY = (float)Math.Atan2((float)direction.X, (float)direction.Z);
            Walk();

        }
        public void MoveTo(IPathMap pathmap, Point destination)
        {
            Vector2 dest = pathmap.ConvertPoint(destination);

            Vector3 positionDest = new Vector3(dest.X, Position.Y, dest.Y);

            MoveTo(positionDest);
        }
        /// <summary>
        /// Esta inativos
        /// </summary>
        public bool IsIdle { get { return isIdle; } }

        /// <summary>
        /// Esta morto
        /// </summary>
        public bool IsDead { get { return isDead; } }

        public bool InRangeOfAttack(IPathMap pathMap, ICharacter character)
        {
            double radius = Math.Sqrt((double)((pathMap.SquareSize.X * pathMap.SquareSize.X) + (pathMap.SquareSize.Y * pathMap.SquareSize.Y)));
            Vector2 target = pathMap.ConvertPoint(character.BoardPosition);
            Vector2 source = pathMap.ConvertPoint(this.BoardPosition);
            float dist = (float) Math.Abs((decimal)Vector2.Distance(target, source));
            if (dist <= radius) return true;
            return false;
        }

        public void Attack(IPathMap pathMap, ICharacter character)
        {
            Vector2 dest = pathMap.ConvertPoint( character.BoardPosition);

            Vector3 targetPosition = new Vector3(dest.X, this.Position.Y, dest.Y);

            Vector3 direction = targetPosition - this.Position;
            direction.Normalize();
            this.RotationY = (float)Math.Atan2((float)direction.X, (float)direction.Z);

            Punch();

            character.TakenDamage(10);

            CurrentMovementPoints--;

        }

        public void TakenDamage(int damage)
        {
            Health -= damage;
            if (Health <= 0) Deading();
        }

        /// <summary>
        /// Define quem será o alvo
        /// </summary>
        /// <returns></returns>
        public ICharacter HowIsTarget(List<ICharacter> listOfCharacters)
        {
            return listOfCharacters[0];
        }

        /// <summary>
        /// Remove objeto
        /// </summary>
        public void SelfRemove() 
        {
            this.Dispose(true);
        }

        #endregion

        #region TurnControl
        public void NewTurn(int turnNumber)
        {
            CurrentMovementPoints = movementPoints;
        }

        #endregion

        #region Methods

        public void Walk()
        {
            this.PlayAnimationClip("Take 001X");
            this.animationPlayer.PlaySpeed = 2;
            this.animationPlayer.Loop = true;
            state = Actions.Andando;
            isIdle = false;
        }

        public void Idle()
        {
            this.PlayAnimationClip("Take 001");
            this.animationPlayer.PlaySpeed = 1;
            this.animationPlayer.Loop = true;
            state = Actions.Parado;
            isIdle = true;
        }

        public void Punch()
        {
            this.PlayAnimationClip("Take 001XX");
            this.animationPlayer.PlaySpeed = 2;
            this.animationPlayer.Loop = false;
            state = Actions.Atacando;
            isIdle = false;
        }

        public void Deading()
        {
            this.PlayAnimationClip("Take 001XX");
            this.animationPlayer.PlaySpeed = 1;
            this.animationPlayer.Loop = false;
            state = Actions.Morrendo;
            isIdle = false;
        }

        public void Dead()
        {
            this.PlayAnimationClip("Take 001XX");
            this.animationPlayer.PlaySpeed = 1;
            this.animationPlayer.Loop = false;
            state = Actions.Morto;
            isIdle = true;
            isDead = true;
        }


        #endregion

        #region Update

        public override void Update(GameTime gameTime)
        {

            base.Update(gameTime);

            switch (state)
            {
                case Actions.Parado:

                    break;

                case Actions.Andando:
                    if (Math.Abs(Vector3.Distance(destination, Position)) < velocity)
                    {
                        Position = destination;
                        Idle();
                    }
                    else
                    {
                        Position += walkdirection * velocity;
                    }
                    break;
                case Actions.Atacando:
                    if (!animationPlayer.Playing) Idle();
                    break;

                case Actions.Morrendo :
                    if (!animationPlayer.Playing) Dead();
                    break;

                default:
                    break;
            }
        }

        #endregion

        #region Draw
        #endregion

    }
}
